Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[staking] ActiveCandidate Exclude Candidate with Expired Endorsement #4062

Merged
merged 10 commits into from
Mar 11, 2024

Conversation

envestcc
Copy link
Member

Description

Since the SelfStake field of a Candidate is not cleared when an endorsement expires, the current ActiveCandidate function does not remove expired candidates. This PR is aimed at fixing this issue.

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • [] make test
  • [] fullsync
  • [] Other test (please specify)

Test Configuration:

  • Firmware version:
  • Hardware:
  • Toolchain:
  • SDK:

Checklist:

  • [] My code follows the style guidelines of this project
  • [] I have performed a self-review of my code
  • [] I have commented my code, particularly in hard-to-understand areas
  • [] I have made corresponding changes to the documentation
  • [] My changes generate no new warnings
  • [] I have added tests that prove my fix is effective or that my feature works
  • [] New and existing unit tests pass locally with my changes
  • [] Any dependent changes have been merged and published in downstream modules

@envestcc envestcc changed the title [staking] ActiveCandidate Exclude Expired Endorsement [staking] ActiveCandidate Exclude Candidate with Expired Endorsement Jan 19, 2024
Copy link

codecov bot commented Jan 19, 2024

Codecov Report

Attention: Patch coverage is 58.33333% with 10 lines in your changes are missing coverage. Please review.

Project coverage is 76.40%. Comparing base (e1f0636) to head (46e75e5).
Report is 192 commits behind head on master.

Files Patch % Lines
action/protocol/staking/protocol.go 60.00% 8 Missing ⚠️
action/protocol/staking/candidate_statereader.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4062      +/-   ##
==========================================
+ Coverage   75.38%   76.40%   +1.02%     
==========================================
  Files         303      340      +37     
  Lines       25923    28984    +3061     
==========================================
+ Hits        19541    22145    +2604     
- Misses       5360     5734     +374     
- Partials     1022     1105      +83     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

}
// bucket is not endorsed to the candidate
if !address.Equal(vb.Candidate, cand.Owner) {
return false, nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this happens, there must be something wrong with our implementation?

Copy link
Member Author

@envestcc envestcc Jan 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed, if clearing candidates is implemented after bucket endorsed to others.

// other error
return false, err
default:
// endorsement does not exist
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return false, nil or return false, ErrNotExist?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is unexpected behaviours, should return error

Comment on lines 505 to 506
// endorsement exists and expired before end of next epoch
rp := rolldpos.MustGetProtocol(protocol.MustGetRegistry(ctx))
currentEpochNum := rp.GetEpochNum(srHeight)
if endorse.Status(rp.GetEpochLastBlockHeight(currentEpochNum+1)) == EndorseExpired {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you elaborate it?

Copy link
Member Author

@envestcc envestcc Jan 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is checking that only nodes whose endorsement have not expired before the end of the next epoch will be considered as consensus nodes. This ensures that self-stake bucket is locked when participate in consensus, which facilitates the introduction of penalty mechanisms in the future.

@@ -513,6 +509,7 @@ func (p *Protocol) isActiveCandidate(ctx context.Context, csr CandidateStateRead
return false, err
default:
// endorsement does not exist
return false, errors.New("endorsement does not exist")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

global variable

vb, err := csr.getBucket(cand.SelfStakeBucketIdx)
if err != nil {
if errors.Is(err, state.ErrStateNotExist) {
return false, nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SelfStakeBucketIndex shouldn't be an invalid one, so we may always return false, err

@@ -116,6 +116,7 @@ type (
SharedGasWithDapp bool
ExecutionSizeLimit32KB bool
UseZeroNonceForFreshAccount bool
DisableDelegateEndorsement bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why DisableDelegateEndorsement not EnableDelegateEndorsement?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the default value for this bool represents the activated state of the new feature, while a default value for bool in Go is false.

@@ -492,7 +538,11 @@ func (p *Protocol) ActiveCandidates(ctx context.Context, sr protocol.StateReader
}
list[i].Votes.Add(list[i].Votes, contractVotes)
}
if list[i].SelfStake.Cmp(p.config.RegistrationConsts.MinSelfStake) >= 0 {
active, err := p.isActiveCandidate(ctx, c, list[i])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are unactive cands included in L527?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two scenarios:

  • The self-stake bucket has been unstaked.
  • The endorsement has expired.

Both situations belong to a registered delegate, but they cannot participate in consensus due to a lack of staking.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. It seems the state of candidates aren't tracked in the db(active/unactive). Pls add ur comments to explain why the list is filtered above L541

Copy link

sonarcloud bot commented Feb 5, 2024

Quality Gate Failed Quality Gate failed

Failed conditions

4.6% Duplication on New Code (required ≤ 3%)

See analysis details on SonarCloud

if cand.SelfStake.Cmp(p.config.RegistrationConsts.MinSelfStake) < 0 {
return false, nil
}
return true, nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just return cand.SelfStake.Cmp(p.config.RegistrationConsts.MinSelfStake) >= 0, nil

}
rp := rolldpos.MustGetProtocol(protocol.MustGetRegistry(ctx))
currentEpochNum := rp.GetEpochNum(srHeight)
return csr.IsActiveCandidateAt(cand, rp.GetEpochLastBlockHeight(currentEpochNum+1))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why should be currentEpochNum+1?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refer to #4062 (comment)

if err != nil {
return nil, err
}
if active {
Copy link
Member

@dustinxie dustinxie Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from the usage here, it is checking current height, not currentEpochNum+1 height

return false, nil
}
esr := NewEndorsementStateReader(c.SR())
endorse, err := esr.Get(cand.SelfStakeBucketIdx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be guarded by hard-fork flag? before 1.14, no such thing as endorsement exist

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

sonarcloud bot commented Mar 11, 2024

Quality Gate Failed Quality Gate failed

Failed conditions
5.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarCloud

@envestcc envestcc merged commit ef4ae12 into iotexproject:master Mar 11, 2024
2 of 5 checks passed
@envestcc envestcc deleted the pr-activecand branch March 11, 2024 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants